<template>
  <Modal
    v-model:active="importModelVueActive"
    transfer
    title="导入"
    :width="540"
    confirm-text="导入"
    @confirm="doUpload"
  >
    <ConfigProvider :props="providedProps">
      <Form :model="formModel" :gap="[0, 0]" :label-width="110">
        <div class="title">
          <div class="title_color"></div>
          <div class="title_content">选择文件</div>
        </div>
        <FormItem :label-width="32">
          <RadioGroup v-model:value="fileOrigin">
            <Radio :label="'local'">本地上传</Radio>
            <Radio :label="'remote'">从云存储选择</Radio>
            <Radio :label="'library'">从模型库选择</Radio>
          </RadioGroup>
        </FormItem>
        <FormItem
          v-if="fileOrigin === 'local'"
          :labelWidth="110"
          label="文件上传:"
          :required="true"
        >
          <Upload
            ref="upload"
            manual
            @change="handleChange"
            buttonLabel="单上传文件"
          ></Upload>
        </FormItem>
        <div v-if="fileOrigin === 'remote'" class="flex mb-20 pl-20">
          <Input class="mr-10 w-300" v-model:value="currentCloudResource" />
          <Button @click="selectFromCloud">从云存储选择</Button>
        </div>
        <div v-if="fileOrigin === 'library'" class="flex mb-20 pl-20">
          <Input class="mr-10 w-300" v-model:value="currentLibraryResource" />
          <Button @click="openModelLibraryModal">从模型库选择</Button>
        </div>
        <Row align="middle" justify="start" :gap="[8]">
          <Column :span="10">
            <FormItem style="margin-bottom: 0" label="缩放:" :labelWidth="110">
              <Checkbox v-model:checked="scaleFlag"></Checkbox>
            </FormItem>
          </Column>
          <Column :span="10">
            <FormItem style="margin-bottom: 0" label="缩放比例=" prop="scale">
              <Input
                v-model:value="formModel.scale"
                :disabled="!scaleFlag"
              ></Input>
            </FormItem>
          </Column>
        </Row>
        <Divider></Divider>
        <div class="title">
          <div class="title_color"></div>
          <div class="title_content">选项</div>
        </div>
        <Row :gap="[8]">
          <Column :span="12">
            <FormItem label="导入类型:">
              <Select
                :options="importTypeOptions"
                v-model:value="importTypeValue"
              ></Select>
            </FormItem>
          </Column>
          <Column :span="10">
            <FormItem label="单位:" :label-width="60">
              <Select
                :options="selectTypeOptions"
                v-model:value="formModel.unitLength"
              ></Select>
            </FormItem>
          </Column>
          <Column style="min-height: 144px" :span="7">
            <FormItem label="追加:">
              <Checkbox v-model:checked="formModel.append"></Checkbox>
            </FormItem>
            <FormItem label="组件作为部件:" prop="splitCompMethod">
              <Checkbox v-model:checked="formModel.splitCompMethod"></Checkbox>
            </FormItem>
            <FormItem label="加载模型颜色:" prop="loadColor">
              <Checkbox v-model:checked="formModel.loadColor"></Checkbox>
            </FormItem>
          </Column>
          <Column style="min-height: 144px" :span="7">
            <FormItem :label-width="100" label="缝合:" prop="fuse">
              <Checkbox v-model:checked="formModel.fuse"></Checkbox>
            </FormItem>
            <FormItem
              :label-width="100"
              label="去除冗余顶点:"
              prop="removeAbundantVertices"
            >
              <Checkbox
                v-model:checked="formModel.removeAbundantVertices"
              ></Checkbox>
            </FormItem>
            <FormItem :label-width="100" label="自动分割:" prop="partition">
              <Checkbox v-model:checked="formModel.partition"></Checkbox>
            </FormItem>
          </Column>
          <Column style="min-height: 144px" :span="10" v-show="formModel.fuse">
            <div class="stitch">
              <div class="stitch-title">缝合选项</div>
              <RadioGroup
                class="mb-10"
                v-model:value="stitch.stitchAll"
                :options="[
                  { content: '全部缝合', label: 1 },
                  { content: '分组缝合', label: 0 },
                ]"
              />
              <Checkbox class="mb-10" v-model:checked="stitch.autoStitchTol"
                >自动缝合容差</Checkbox
              >
              <FormItem class="mb-10" :label-width="60" label="缝合容差: ">
                <Input
                  size="small"
                  v-model:value="stitch.stitchTol"
                  :disabled="stitch.autoStitchTol"
                />
              </FormItem>
              <Checkbox v-model:checked="stitch.nonManifold">非流型</Checkbox>
            </div>
          </Column>
        </Row>
      </Form>
    </ConfigProvider>
  </Modal>
</template>
<script setup lang="ts">
import { ref, reactive } from "vue";
import { PlyActor, StlActor, VtkActor, ObjActor } from "cax-base";
import {
  Modal,
  Divider,
  Form,
  FormItem,
  ConfigProvider,
  Checkbox,
  Column,
  Input,
  Row,
  Select,
  Upload,
  Toast,
  Message,
  Radio,
  RadioGroup,
  Button,
} from "cax-ui";

import { storeToRefs } from "pinia";
import { useCoreStore, _global } from "@/UI/store";
import type { UploadExposed, UploadFileState } from "cax-ui";
import {
  S3Client,
  HeadObjectCommand,
  PutObjectCommand,
} from "@aws-sdk/client-s3";
import { Buffer } from "buffer";

import { onMounted } from "vue";
import { FileLoadOptions, MODEL_TYPE, TEMPLATE_TYPE } from "@/FrontProcessing";

import { oss, Bucket, AppEvent } from "@/UI/config";

const coreStore = useCoreStore();

coreStore.Notify.subscribe((msg: any) => {
  if (msg.type === AppEvent.MODEL_LIBRARY_SELECTED) {
    const url = msg.data;
    coreStore.setCurrentLibraryResource(url);
  }
});

const providedProps = {
  default: { clearable: true },
  formItem: { required: false },
};
const formModel = reactive({
  scale: "2.0",
  fuse: false,
  unitLength: 1,
  append: false,
  loadColor: false,
  removeAbundantVertices: false,
  partition: false,
  splitCompMethod: false,
});

// 缝合选项
const stitch = reactive({
  autoStitchTol: true,
  nonManifold: false,
  stitchAll: 0,
  stitchTol: 0,
});
const fileList = ref();
const selectTypeOptions = [
  {
    label: "毫米(mm)",
    value: 1,
  },
  {
    label: "厘米(cm)",
    value: 2,
  },
];

const importTypeValue = ref<number>(0);
const importTypeOptions = [
  {
    label: TEMPLATE_TYPE.GEOMETRY,
    value: 0,
  },
  {
    label: TEMPLATE_TYPE.NASTRAN,
    value: 1,
  },
  {
    label: TEMPLATE_TYPE.ABAQUS,
    value: 2,
  },
  {
    label: TEMPLATE_TYPE.ANSYS,
    value: 3,
  },
  {
    label: TEMPLATE_TYPE.LSDYNA,
    value: 4,
  },
  {
    label: TEMPLATE_TYPE.HDF5,
    value: 5,
  },
  {
    label: TEMPLATE_TYPE.CGNS,
    value: 6,
  },
];

const modelPath = ref("C:\\Users\\Chris\\Downloads\\stp_demo\\Box.stp");

let s3Client: any = null;

const scaleFlag = ref(false); // 缩放

let { importModelVueActive, currentCloudResource, currentLibraryResource } =
  storeToRefs(coreStore);

/**
 * * 文件来源
 */
const fileOrigin = ref("local");

onMounted(() => {
  s3Client = new S3Client(oss());
});

function getLastPartAfterDot(inputString: string): string {
  const lastDotIndex = inputString.lastIndexOf(".");
  if (lastDotIndex === -1) {
    // 如果字符串中没有'.'，返回整个字符串
    return inputString;
  } else {
    // 返回'.'后面的部分
    return inputString.substring(lastDotIndex + 1);
  }
}
// 文件分类处理
function parseFileBuffer(
  arrayBuffer: ArrayBuffer,
  type: string,
  filename: string
) {
  const handleModel = (ActorClass: any) => {
    load2minio(filename, arrayBuffer).then((url) => {
      const model = new ActorClass(url);
      _global.Engine.model.add(model);
    });
  };

  switch (type) {
    case "stl":
      handleModel(StlActor);
      break;
    case "ply":
      handleModel(PlyActor);
      break;
    case "vtk":
      handleModel(VtkActor);
      break;
    case "obj":
      handleModel(ObjActor);
      break;
    default:
      loadStpOrBdfFile(arrayBuffer, filename);
      break;
  }
}

async function load2minio(filename: string, arrayBuffer: ArrayBuffer) {
  Toast.loading({ content: "上传中", duration: 0 });
  // 上传文件到 MinIO
  let path = ref();
  let key = `model/${filename}`;
  const fileExists = await checkIfFileExists(Bucket(), key);
  if (!fileExists) {
    const buffer = Buffer.from(arrayBuffer);
    await uploadFile(buffer, Bucket(), key);
  }
  coreStore.setFilename(filename); // 每次上传文件修改store中的filename
  path.value = `${oss().endpoint}/${Bucket()}/${key}`;
  Toast.close();
  if (path.value == undefined) {
    alert("path.value == undefined文件上传失败，请重试。");
    return;
  }
  return path.value;
}

// 是否允许追加导入多个bdf文件
async function loadStpOrBdfFile(arrayBuffer: ArrayBuffer, filename: string) {
  // 1. 导入step文件之后，无法追加导入bdf文件。除非，先导入bdf文件，再导入step文件。
  if (!formModel.append) {
    // 不追加情况下
    _global.Engine.model.clear();
  }

  Toast.loading({ content: "上传中", duration: 0 });

  // 上传文件到 MinIO
  let path = ref();
  let key = `model/${filename}`;
  const fileExists = await checkIfFileExists(Bucket(), key);
  if (!fileExists) {
    const buffer = Buffer.from(arrayBuffer);
    const uploadResponse = await uploadFile(buffer, Bucket(), key);
  }
  coreStore.setFilename(filename); // 每次上传文件修改store中的filename
  path.value = `${oss().endpoint}/${Bucket()}/${key}`;
  Toast.close();
  // console.log("path", path.value);
  if (path.value == undefined) {
    alert("path.value == undefined文件上传失败，请重试。");
    return;
  }
  //设置结果和路径
  res.value = {
    path: path.value,
    result: 1,
  };
  importModelVueActive.value = false;
  modelPath.value = path.value;

  //文件扩展名中获取文件类型
  const extension = filename.split(".").pop()?.toLowerCase() || "";
  console.log("extension", extension);
  const fileType = FILE_TYPE_MAP[extension as keyof typeof FILE_TYPE_MAP] ?? 0;
  console.log("fileType", fileType);

  if (fileType !== undefined) {
    importTypeValue.value = fileType;
  } else {
    importTypeValue.value = 0;
    console.warn(`未知文件类型: ${extension}, 默认使用geometry类型`);
  }

  //加载状态
  Toast.loading({ content: "加载中", duration: 0 });

  const option: FileLoadOptions = {
    path: modelPath.value,
    type: MODEL_TYPE.GY,
    importType: getImportType(),
    append: formModel.append,
  };
  console.log("options", option);
  if (formModel.fuse) {
    option.fuse = 1;
    option.stitch = {
      stitchAll: stitch.stitchAll ? 1 : 0,
      autoStitchTol: stitch.autoStitchTol ? 1 : 0,
      nonManifold: stitch.nonManifold ? 1 : 0,
      stitchTol: stitch.stitchTol,
    };
  }
  const keys: Array<"loadColor" | "removeAbundantVertices" | "partition"> = [
    "loadColor",
    "removeAbundantVertices",
    "partition",
  ];
  keys.forEach((key) => {
    option[key] = formModel[key] ? 1 : 0;
  });
  if (scaleFlag.value) option.scale = Number(formModel.scale);
  if (formModel.splitCompMethod) option.splitCompMethod = 2;
  if (formModel.unitLength) option.splitCompMethod = formModel.unitLength;

  _global.Engine.file
    .stp_or_bdf_file_load(option)
    .then((result: any) => {
      coreStore.setBomInfo(result);
      console.log("外部获取装配信息", result);
    })
    .catch((err) => {
      Message.error(err);
    })
    .finally(() => {
      fileList.value = [];
      modelPath.value = "";
      _global.Engine.view.autoAdapt();
      Toast.close();
    });
  Message.success("上传成功!");
}

// 暂时写死bdf
function loadHttpFile(url: string) {
  //加载状态
  Toast.loading({ content: "加载中", duration: 0 });

  const option: FileLoadOptions = {
    path: url,
    type: MODEL_TYPE.GY,
    importType: getImportType(),
    append: formModel.append,
  };
  if (formModel.fuse) {
    option.fuse = 1;
    option.stitch = {
      stitchAll: stitch.stitchAll ? 1 : 0,
      autoStitchTol: stitch.autoStitchTol ? 1 : 0,
      nonManifold: stitch.nonManifold ? 1 : 0,
      stitchTol: stitch.stitchTol,
    };
  }
  const keys: Array<"loadColor" | "removeAbundantVertices" | "partition"> = [
    "loadColor",
    "removeAbundantVertices",
    "partition",
  ];
  keys.forEach((key) => {
    option[key] = formModel[key] ? 1 : 0;
  });
  if (scaleFlag.value) option.scale = Number(formModel.scale);
  if (formModel.splitCompMethod) option.splitCompMethod = 2;
  if (formModel.unitLength) option.splitCompMethod = formModel.unitLength;

  _global.Engine.file
    .stp_or_bdf_file_load(option)
    .then((result: any) => {
      coreStore.setBomInfo(result);
      console.log("外部获取装配信息", result);
    })
    .catch((err) => {
      Message.error(err);
    })
    .finally(() => {
      fileList.value = [];
      modelPath.value = "";
      _global.Engine.view.autoAdapt();
      Toast.close();
    });
  Message.success("上传成功!");
}

const readFileAsArrayBuffer = (file: File): Promise<ArrayBuffer> => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result as ArrayBuffer);
    reader.onerror = reject;
    reader.readAsArrayBuffer(file);
  });
};

// 检查文件是否存在
const checkIfFileExists = async (bucketName: string, objectKey: string) => {
  try {
    const command = new HeadObjectCommand({
      Bucket: bucketName,
      Key: objectKey,
    });
    await s3Client.send(command);
    return true;
  } catch (error: any) {
    if (error.name === "NotFound") {
      return false;
    }
    throw error;
  }
};

// 上传文件到 MinIO
const uploadFile = async (file: any, bucketName: string, objectKey: string) => {
  const command = new PutObjectCommand({
    Bucket: bucketName,
    Key: objectKey,
    Body: file,
  });
  try {
    const response = await s3Client.send(command);
    return {
      Location: `${
        location.href.includes("dev") ? "http://127.0.0.1:9000" : oss().endpoint
      }/${Bucket()}/${objectKey}`,
    };
  } catch (error) {
    alert(`文件上传失败，请重试。${error}`);
    return;
  }
};

function getImportType() {
  console.log("importTypeValue", importTypeValue.value);
  return importTypeOptions[importTypeValue.value].label;
}

// 判断文件是否为bdf文件
function isBdfFile(path: string) {
  return path.toLowerCase().endsWith(".bdf");
}

//创建 文件扩展名->文件类型 的映射
const FILE_TYPE_MAP = {
  // Geometry文件
  stp: 0, // geometry
  brep: 0, //geometry
  iges: 0, //geometry
  obj: 0, //geometry
  // Nastran文件
  bdf: 1, // nastran
  // Abaqus文件
  inp: 2, // abaqus
  // ANSYS文件
  cdb: 3, // ansys
  // LsDyna文件
  key: 4, // lsdyna
  k: 4, // lsdyna
  // 通用文件格式
  h5: 5, // hdf5
  cgns: 6, // cgns
};

// 未设置 url 时，可以通过 change 事件记录选择的文件，后续自行操作，如放入 FormData 中
function handleChange(files: UploadFileState[]) {
  fileList.value = files;
  // if (isBdfFile(fileList.value?.[0].name)) {
  //   importTypeValue.value = 1; // nastran
  // } else {
  //   importTypeValue.value = 0; // geometry
  // }

  if (!files.length) return;

  const fileName = files[0].name;
  const extension = fileName.split(".").pop()?.toLowerCase() || "";

  // 使用映射获取类型值，如果未找到则默认为geometry(0)
  importTypeValue.value =
    FILE_TYPE_MAP[extension as keyof typeof FILE_TYPE_MAP] ?? 0;
}

const upload = ref<UploadExposed>();

let res = ref({});

// 设置了 url 时，可以通过 ref 获取组件并调用 execute 进行上传
async function doUpload() {
  if (!upload.value && fileOrigin.value === "local") return;
  if (fileOrigin.value === "local") {
    //   if (isBdfFile(fileList.value?.[0].name) && importTypeValue.value != 1) {
    //     alert("bdf文件的导入类型必须为nastran");
    //     return;
    //   }
    //   if (!isBdfFile(fileList.value?.[0].name) && importTypeValue.value == 1) {
    //     alert("几何文件的导入类型必须为geometry");
    //     return;
    //   }
    let file = fileList.value?.[0];

    //根据扩展名显示信息
    const extension = file.name.split(".").pop()?.toLowerCase() || "";
    const expecctedFileType =
      FILE_TYPE_MAP[extension as keyof typeof FILE_TYPE_MAP] ?? 0;
    if (
      expecctedFileType !== undefined &&
      expecctedFileType !== importTypeValue.value
    ) {
      alert(
        `文件类型不匹配，期望文件类型为${importTypeOptions[expecctedFileType].label}`
      );
      return;
    }

    let arrayBuffer: ArrayBuffer = await readFileAsArrayBuffer(file.source);
    parseFileBuffer(arrayBuffer, getLastPartAfterDot(file.name), file.name);
  }

  if (fileOrigin.value === "remote") {
    parseFileBuffer(
      new ArrayBuffer(10),
      getLastPartAfterDot(coreStore.currentCloudResource),
      coreStore.currentCloudResource
    );
  }

  if (fileOrigin.value === "library") {
    loadHttpFile(coreStore.currentLibraryResource);
  }
}

function selectFromCloud() {
  coreStore.changeCloudResourceSelectModalActive(true);
}

function openModelLibraryModal() {
  coreStore.setImportCloudFileModalVueActive(true);
}
</script>

<style scoped lang="less">
.title {
  display: flex;
  align-items: center;
  width: 100%;
  padding: 0 16px;
  margin-bottom: 16px;

  .title_color {
    width: 4px;
    height: 12px;
    background: #339af0;
    margin-right: 8px;
  }

  .title_content {
    opacity: 1;
    font-family: PingFang SC;
    font-size: 14px;
    font-weight: 600;
    line-height: 22px;
    letter-spacing: 0em;
    font-variation-settings: "opsz" auto;
    /* content/主要一级primary */
    /* 样式描述：--vxp-content-color-primary */
    color: #212529;
  }
}
.stitch {
  padding: 16px 12px 12px;
  position: relative;
  border: var(--vxp-border-base);
  border-radius: 4px;
  &-title {
    position: absolute;
    top: -8px;
    left: 8px;
    padding: 0 6px;
    background-color: var(--vxp-bg-color-base);
  }
}
</style>
